#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#define START		100
#define END			300
#define THR_COUNT	4	// 要开几个线程来计算

static int is_prime(int num);

static void *thr_job(void *s);

// job == 0		新的任务未发放
// job > 0		发放的任务未取走
// job == -1	所有任务发放完
static int job;

static int cnt;

static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;

static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static pthread_mutex_t cnt_mut = PTHREAD_MUTEX_INITIALIZER;

int main(void)
{
	pthread_t tids[THR_COUNT];
	int args[][THR_COUNT] = {{0}, {1}, {2}, {3}}; // 新线程的启动参数，分别传给四个线程
	int err, i;

	for (i = 0; i < THR_COUNT; i++) {
		err = pthread_create(&tids[i], NULL, thr_job, (void *) args[i]);

		if (err) {
			fprintf(stderr, "Error creating thread: %s\n", strerror(err));
			exit(1);
		}
	}

	for (i = START; i <= END; i++) { // 发放任务
		pthread_mutex_lock(&mut);
		while (job > 0) {
			//pthread_mutex_unlock(&mut);
			//pthread_mutex_lock(&mut);
			pthread_cond_wait(&cond, &mut);
		}
		job = i;
		pthread_cond_signal(&cond);
		pthread_mutex_unlock(&mut);
	}

	pthread_mutex_lock(&mut);
	while (job > 0) {
		//pthread_mutex_unlock(&mut);
		//pthread_mutex_lock(&mut);
		pthread_cond_wait(&cond, &mut);
	}
	job = -1;
	pthread_cond_broadcast(&cond);
	pthread_mutex_unlock(&mut);

	for (i = 0; i < THR_COUNT; i++) { // 分别给每个线程収尸
		pthread_join(tids[i], NULL);
	}

	printf("Total count: %d\n", cnt);

	pthread_mutex_destroy(&mut);
	pthread_mutex_destroy(&cnt_mut);

	return 0;
}

static int is_prime(int num)
{
	int i;

	for (i = 2; i < num / 2; i++) {
		if (num % i == 0) {
			return 0;
		}
	}

	return 1;
}

static void *thr_job(void *s)
{
	int t = ((int *) s)[0]; // 第几个线程
	int value;

	while (1) {
		pthread_mutex_lock(&mut);
		while (job == 0) {
			//pthread_mutex_unlock(&mut);
			//pthread_mutex_lock(&mut);
			pthread_cond_wait(&cond, &mut);
		}
		if (job == -1) {
			pthread_mutex_unlock(&mut);
			break;
		}

		value = job;
		job = 0;

		pthread_cond_broadcast(&cond);
		pthread_mutex_unlock(&mut);

		if (is_prime(value)) {
			printf("Thread [%d]: %d is prime\n", t, value);
			pthread_mutex_lock(&cnt_mut);
			cnt++;
			pthread_mutex_unlock(&cnt_mut);
		}
	}

	return (void *) 0;
}

